#pragma once
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string>
#include"log.hpp"
#include<unordered_map>

Log lg;
const uint16_t defaultport=8808;
const std::string defaultip="0.0.0.0";
enum{
    SOCK_ERR=1,
    BIND_ERR
};
class UdpServer
{
    private:
    int sock_fd;//网络文件描述符
    uint16_t port_;//端口
    std::string ip_;//ip
    std::unordered_map<std::string, sockaddr_in> online_user;
    public:
    UdpServer(const uint16_t&port=defaultport,const std::string &ip=defaultip)
    :port_(port),ip_(ip)
    {

    }
    void Initialize()
    {
        //1.创建套接字
        sock_fd=socket(AF_INET,SOCK_DGRAM,0);
        if(sock_fd<0)
        {
            lg(FATAL,"Sock create fail!! errno is: %d, errstring is: %s",errno,strerror(errno));
            exit(SOCK_ERR);
        }
        lg(INFO,"Sock create sucess!! sockfd is: %d",sock_fd);
        //2.数据准备
        struct sockaddr_in server;
        memset(&server,0,sizeof(server));//初始化结构体
        inet_aton(ip_.c_str(),&server.sin_addr);//字符串转地址
        server.sin_family=AF_INET;
        server.sin_port=htons(port_);//主机转网络字节序
        //3.bind
        if(bind(sock_fd,(sockaddr*)&server,sizeof(server))<0)
        {
            lg(FATAL,"Bind fail!! errno is: %d,errstring is: %s",errno,strerror(errno));
            exit(BIND_ERR);
        }
        lg(INFO,"Bind sucess!! sockfd is: %d",sock_fd);
    }
    void CheckUser(const uint16_t&port,const std::string&ip,sockaddr_in&client)
    {
        auto iter=online_user.find(ip);
        if(iter!=online_user.end())return;
        online_user.insert({ip,client});
        std::cout<<"["<<port<<":"<<ip<<"]"<<"# user login...."<<std::endl;
    }
    void Broadcast(const uint16_t&port,const std::string&ip,const std::string& info)
    {
        std::string message="[";
        message+=std::to_string(port);
        message+=":";
        message+=ip;
        message+="]#:";
        std::string echo_message=message+info;
        for(auto &e:online_user)
        {
            sendto(sock_fd,echo_message.c_str(),echo_message.size(),0,(sockaddr*)(&e.second),sizeof(e.second));
        }
    }
    void Start()
    {
        char buffer[1024];//读入的缓冲区
       
        while(true)
        {
            //1.读
             struct sockaddr_in client;//用来获取客户端信息
        socklen_t len=sizeof(client);
            ssize_t n=recvfrom(sock_fd,buffer,sizeof(buffer),0,(sockaddr*)&client,&len);
            if(n<0)
            {
                continue;//读取失败继续读
            }
           else if(n>0)
            {
                buffer[n]='\0';
                std::string info=buffer;
                uint16_t clientport=ntohs(client.sin_port);//网络转主机字节序
                char ipstr[32];
                inet_ntop(AF_INET,&client.sin_addr,ipstr,sizeof(ipstr));//地址转字符串
                std::string clientip=ipstr;
                CheckUser(clientport,clientip,client);//检查用户是否存在
                Broadcast(clientport,clientip,info);//转发客户端的信息给每个用户
            }
        }
    }
    ~UdpServer()
    {
        if(sock_fd>0)close(sock_fd);
    }

};